package webmarket.jpacontrollers;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class PredicateBuilder {

	private static final Logger logger = LogManager.getLogger();

	/**
	 * Concats param to result, if not null (with AND)
	 * 
	 * @param cb
	 * @param result
	 * @param other
	 * @return
	 */
	public static Predicate concatPredicate(CriteriaBuilder cb, Predicate result, Predicate other) {
		if (other != null) {
			return cb.and(result, other);
		}
		return result;
	}

	/**
	 * Concats all given predicates into a final predicate, with AND connection
	 * 
	 * @param cb
	 * @param preds
	 * @return
	 */
	public static Predicate concatAllPredicates(CriteriaBuilder cb, Predicate... preds) {
		Predicate result = cb.conjunction();
		for (Predicate pred : preds) {
			result = concatPredicate(cb, result, pred);
		}
		return result;
	}

	/**
	 * Creates a predicate for a parameter between two bounds If one of them is
	 * not given, it is not taken into account
	 * 
	 * @param cb
	 * @param property
	 * @param lower
	 * @param upper
	 * @return
	 */
	public static <T extends Comparable<? super T>> Predicate createRangePredicate(CriteriaBuilder cb,
			Expression<? extends T> property,
			T lower,
			T upper) {
		Predicate root = cb.conjunction();
		if (lower != null) {

			root = cb.and(cb.greaterThanOrEqualTo(property, lower), root);
		}

		if (upper != null) {
			root = cb.and(cb.lessThanOrEqualTo(property, upper), root);
		}
		return root;
	}

	/**
	 * Creates range predicate for IP search
	 * 
	 * @param cb
	 * @param ipexp
	 * @param ipfrom
	 * @param ipto
	 * @return
	 */
	public static Predicate createIpPredicate(CriteriaBuilder cb, Expression<String> ipexp, String ipfrom, String ipto) {
		Predicate pIp = cb.conjunction();
		if (!"000.000.000.000".equals(ipfrom)) {
			pIp = cb.and(cb.greaterThanOrEqualTo(ipexp, ipfrom), pIp);
		}

		if (!"255.255.255.255".equals(ipto)) {
			pIp = cb.and(cb.lessThanOrEqualTo(ipexp, ipto), pIp);
		}
		return pIp;
	}

	/**
	 * Creates a predicate for a multiselect input
	 * 
	 * @param cb
	 * @param property
	 * @param values
	 * @return
	 */
	public static <T extends Comparable<? super T>> Predicate createMultiselectPredicate(CriteriaBuilder cb,
			Expression<? extends T> property,
			T[] values) {
		Predicate pSelect = cb.conjunction();
		for (T role : values) {
			pSelect = cb.or(cb.equal(property, role), pSelect);
		}
		return pSelect;
	}

	/**
	 * Creates a predicate for a simple text inpu
	 * 
	 * @param cb
	 * @param propertyexp
	 * @param value
	 * @return
	 */
	public static <T> Predicate createLikePredicate(CriteriaBuilder cb, Expression<String> propertyexp, String value) {
		Predicate pLike = cb.conjunction();
		if (!StringUtils.isBlank(value)) {
			pLike = cb.and(cb.like(propertyexp, "%" + value + "%"), pLike);
			logger.debug("Created like predicate: " + propertyexp.getAlias() + " LIKE " + value);
		}
		return pLike;
	}

	/**
	 * Creates predicate for an active select input (values:
	 * 'active'/'inactive'/'both')
	 * 
	 * @param cb
	 * @param activeexp
	 * @param active
	 * @return
	 */
	public static Predicate createActivePredicate(CriteriaBuilder cb, Expression<Boolean> activeexp, String active) {
		Predicate pActive = cb.conjunction();
		switch (active) {
		case "active":
			pActive = cb.and(cb.equal(activeexp, true), pActive);
			break;
		case "inactive":
			pActive = cb.and(cb.equal(activeexp, false), pActive);
			break;
		default:
			break;
		}
		return pActive;
	}

}
